
{***********************************************************}
{                                                           }
{      Informix Data Access Components                      }
{                                                           }
{      Error handling and global IDAC events                }
{                                                           }
{      Copyright (c) 2001-2008 Luxena Software Company      }
{      http://www.luxena.com                                }
{      e-mail: support@luxena.com                           }
{                                                           }
{***********************************************************}

unit Ifx;

{$I lx.inc}

interface

uses
  Classes, DB;

type

{ EIDACError }

  EIDACError = class(EDatabaseError);


{ EIfxError }

  EIfxError = class(EDatabaseError)
  private
    FSQL: Integer;
    FISAM: Integer;
  public
    constructor Create(const Msg: string; SQL, ISAM: Integer);
    property SQL: Integer read FSQL;
    property ISAM: Integer read FISAM;
  end;


{ TIDACEvents }

  TIDACEvents = class(TComponent)
  private
    FOnObjectCreate: TNotifyEvent;
    FOnObjectLoaded: TNotifyEvent;
    FOnObjectDestroy: TNotifyEvent;
    procedure DoObjectCreate(Sender: TObject);
    procedure DoObjectLoaded(Sender: TObject);
    procedure DoObjectDestroy(Sender: TObject);
  public
    class procedure HandleObjectCreate(Sender: TObject);
    class procedure HandleObjectLoaded(Sender: TObject);
    class procedure HandleObjectDestroy(Sender: TObject);
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property OnObjectCreate: TNotifyEvent read FOnObjectCreate write FOnObjectCreate;
    property OnObjectLoaded: TNotifyEvent read FOnObjectLoaded write FOnObjectLoaded;
    property OnObjectDestroy: TNotifyEvent read FOnObjectDestroy write FOnObjectDestroy;
  end;


{ Global routines }

procedure IDACError(const Msg: string; Component: TComponent = nil);
procedure IDACErrorFmt(const Msg: string; const Args: array of const;
  Component: TComponent = nil);

function GetInformixMessage(Status: Integer): string;
function CheckInformixResult(Status: Integer): Integer;


implementation

uses
  SysUtils, IfxConsts, IfxIntf, LXIDAC;


{ EIfxError }

constructor EIfxError.Create(const Msg: string; SQL, ISAM: Integer);
begin
  inherited Create(Msg);
  FSQL := SQL;
  FISAM := ISAM;
end;


{ TIDACEvents }

var
  globalIDACEventsList: TThreadList;

class procedure TIDACEvents.HandleObjectCreate(Sender: TObject);
var
  I: Integer;
begin
  with globalIDACEventsList.LockList do
    try
      for I := 0 to Count - 1 do
        TIDACEvents(Items[I]).DoObjectCreate(Sender);
    finally
      globalIDACEventsList.UnlockList;
    end;
end;

class procedure TIDACEvents.HandleObjectLoaded(Sender: TObject);
var
  I: Integer;
begin
  with globalIDACEventsList.LockList do
    try
      for I := 0 to Count - 1 do
        TIDACEvents(Items[I]).DoObjectLoaded(Sender);
    finally
      globalIDACEventsList.UnlockList;
    end;
end;

class procedure TIDACEvents.HandleObjectDestroy(Sender: TObject);
var
  I: Integer;
begin
  with globalIDACEventsList.LockList do
    try
      for I := 0 to Count - 1 do
        TIDACEvents(Items[I]).DoObjectDestroy(Sender);
    finally
      globalIDACEventsList.UnlockList;
    end;
end;

constructor TIDACEvents.Create(AOwner: TComponent);
begin
  inherited;
  globalIDACEventsList.Add(Self);
end;

destructor TIDACEvents.Destroy;
begin
  globalIDACEventsList.Remove(Self);
  inherited;
end;

procedure TIDACEvents.DoObjectCreate(Sender: TObject);
begin
  if Assigned(FOnObjectCreate) then FOnObjectCreate(Sender);
end;

procedure TIDACEvents.DoObjectLoaded(Sender: TObject);
begin
  if Assigned(FOnObjectLoaded) then FOnObjectLoaded(Sender);
end;

procedure TIDACEvents.DoObjectDestroy(Sender: TObject);
begin
  if Assigned(FOnObjectDestroy) then FOnObjectDestroy(Sender);
end;


{ Global routines }

procedure IDACError(const Msg: string; Component: TComponent = nil);
begin
  if Assigned(Component) and (Component.Name <> '') then
    raise EIDACError.Create(Format('%s: %s', [Component.Name, Msg])) else
    raise EIDACError.Create(Msg);
end;

procedure IDACErrorFmt(const Msg: string; const Args: array of const;
  Component: TComponent = nil);
begin
  IDACError(Format(Msg, Args), Component);
end;

function GetInformixMessage(Status: Integer): string;
const
  MAX_ERROR_MSG_LEN = $7fff;
var
  MsgResult: Integer;
  MsgLength: Integer;
begin
  SetString(Result, nil, MAX_ERROR_MSG_LEN + 1);
  MsgResult := rgetlmsg(Status, PChar(Result), MAX_ERROR_MSG_LEN, @MsgLength);

  if MsgResult <> 0 then
    Result := Format(SErrorMsgFailure, [MsgResult]) else
  begin
    SetLength(Result, MsgLength);
    Result := Format(Result, [fnsqlca^.sqlerrm]);
  end;
end;

function CheckInformixResult(Status: Integer): Integer;
var
  SqlErrorMsg: string;
  IsamError: Integer;
  IsamErrorMsg: string;
begin
  CheckLicense;

  Result := Status;
  if Result >= 0 then Exit;

  SqlErrorMsg := Format(SSQLError, [Status, GetInformixMessage(Status)]);

  IsamError := fnsqlca^.sqlerrd[1];
  if IsamError <> 0 then
  begin
    if IsamError > 0 then
      IsamErrorMsg := Format(SISAMMessage, [IsamError]) else
      IsamErrorMsg := Format('%d ', [IsamError]);
    IsamErrorMsg := IsamErrorMsg + GetInformixMessage(IsamError);
  end;

  raise EIfxError.Create(SqlErrorMsg + IsamErrorMsg, Result, IsamError);
end;


initialization
  globalIDACEventsList := TThreadList.Create;

finalization
  FreeAndNil(globalIDACEventsList);

end.